#region CVS Log
/*
 * Version:
 *   $Id: GEOBFrame.cs,v 1.8 2004/11/20 23:12:12 cwoodbury Exp $
 *
 * Revisions:
 *   $Log: GEOBFrame.cs,v $
 *   Revision 1.8  2004/11/20 23:12:12  cwoodbury
 *   Removed TextEncodingType.ASCII type; replaced with ISO_8859_1 type
 *   or default type for EncodedString.
 *
 *   Revision 1.7  2004/11/16 07:08:14  cwoodbury
 *   Changed accessibility modifiers for some methods to internal or
 *   protected internal where appropriate.
 *
 *   Revision 1.6  2004/11/16 06:43:39  cwoodbury
 *   Fixed bug #1066848: EncodedStrings.CreateEncodedStrings() corrupted
 *   data in the optional leftover bytes.
 *
 *   Revision 1.5  2004/11/10 07:32:29  cwoodbury
 *   Factored out ParseFrameData() into ID3v2Frame.
 *
 *   Revision 1.4  2004/11/10 06:51:55  cwoodbury
 *   Hid CVS log messages away in #region
 *
 *   Revision 1.3  2004/11/10 06:31:14  cwoodbury
 *   Updated documentation.
 *
 *   Revision 1.2  2004/11/10 04:44:16  cwoodbury
 *   Updated documentation.
 *
 *   Revision 1.1  2004/11/03 01:18:50  cwoodbury
 *   Added to ID3Sharp
 *
 */
#endregion

/* 
 * Author(s):
 *   Chris Woodbury 
 * 
 * Project Location:
 *	 http://id3sharp.sourceforge.net
 * 
 * License:
 *   Licensed under the Open Software License version 2.0
 */

using System;
using System.IO;
using System.Collections;

using ID3Sharp.IO;

namespace ID3Sharp.Frames
{
	/// <summary>
	/// An Encapsulated-Object frame.
	/// </summary>
	public class GEOBFrame : ID3v2Frame
	{
		#region Fields
		/// <summary>
		/// The contents of the MIME-Type field.
		/// </summary>
		private EncodedString mimeType;
		/// <summary>
		/// The contents of the Filename field.
		/// </summary>
		private EncodedString filename;
		/// <summary>
		/// The contents of the Description field.
		/// </summary>
		private EncodedString description;
		/// <summary>
		/// The contents of the Encapsulated Object field.
		/// </summary>
		private byte[] encapsulatedObject;
		#endregion

		#region Constructors
		/// <summary>
		/// Creates a new GEOBFrame.
		/// </summary>
		protected internal GEOBFrame()
		{
			mimeType = new EncodedString( TextEncodingType.ISO_8859_1, "" );
			filename = new EncodedString();
			description = new EncodedString();
			encapsulatedObject = new byte[] {};
		}
		#endregion

		#region Constructor/Initialize helpers
		/// <summary>
		/// Parses the raw frame data.
		/// </summary>
		/// <param name="frameData">The raw frame data.</param>
		/// <param name="version">The ID3v2 version of the tag being parsed.</param>
		protected override void ParseFrameData( byte[] frameData, ID3Versions version )
		{
			// Encoding type
			TextEncodingType encType = (TextEncodingType) frameData[0];

			// MIME type
			int mimeEnd = FindNull( frameData, 1 );
			byte[] mimeBytes = new byte[ mimeEnd - 1 ];
			Array.Copy( frameData, 1, mimeBytes, 0, mimeBytes.Length );
			mimeType = new EncodedString( TextEncodingType.ISO_8859_1, mimeBytes );
			

			byte[] remainingBytes = new byte[ (frameData.Length - mimeEnd) - 1 ];
			Array.Copy( frameData, mimeEnd + 1, remainingBytes, 0, remainingBytes.Length );
			ArrayList strings = EncodedString.CreateEncodedStrings( encType, remainingBytes, 2 );
			filename = (EncodedString) strings[0];
			description = (EncodedString) strings[1];
			encapsulatedObject = (byte[]) strings[2];
		}

		/// <summary>
		/// Returns the index of the next null byte in a byte array.
		/// </summary>
		/// <param name="data">The byte array to search.</param>
		/// <param name="currentIndex">The index at which to start looking.</param>
		/// <returns>The index of the next null byte in a byte array.</returns>
		private static int FindNull( byte[] data, int currentIndex )
		{
			for( ; currentIndex < data.Length; currentIndex++ )
			{
				if ( data[ currentIndex ] == 0x0 )
				{
					break;
				}
			}

			return currentIndex;
		}
		#endregion

		#region Properties
		/// <summary>
		/// Gets the size (in bytes) of the frame (not including header).
		/// </summary>
		public override int Size
		{
			get
			{
				// encoding description byte +  ...
				return 1 + encapsulatedObject.Length + mimeType.Size + filename.Size + description.Size +
					mimeType.Termination.Length + filename.Termination.Length + description.Termination.Length;
			}
		}
		
		/// <summary>
		/// Gets and sets the contents of the MIME-Type field.
		/// </summary>
		public string MIMEType
		{
			get
			{
				return mimeType.String;
			}
			set
			{
				mimeType.String = value;
			}
		}

		/// <summary>
		/// Gets and sets the contents of the Filename field.
		/// </summary>
		public string Filename
		{
			get
			{
				return filename.String;
			}
			set
			{
				filename.String = value;
			}
		}

		/// <summary>
		/// Gets and sets the contents of the Description field.
		/// </summary>
		public string Description
		{
			get
			{
				return description.String;
			}
			set
			{
				description.String = value;
			}
		}


		/// <summary>
		/// Gets and sets the contents of the Encapsulated Object field.
		/// </summary>
		public byte[] EncapsulatedObject
		{
			get
			{
				return encapsulatedObject;
			}
			set
			{
				encapsulatedObject = value;
			}
		}
		#endregion

		/// <summary>
		/// Returns a copy of this frame. Supports the prototype design pattern.
		/// </summary>
		/// <returns>A copy of this frame.</returns>
		public override ID3v2Frame Copy()
		{
			GEOBFrame frameCopy = new GEOBFrame();
			frameCopy.mimeType = new EncodedString( this.mimeType.TextEncodingType, this.mimeType.String );
			frameCopy.filename = new EncodedString( this.filename.TextEncodingType, this.filename.String );
			frameCopy.description = new EncodedString( this.description.TextEncodingType, this.description.String );
			byte[] objectCopy = new byte[ encapsulatedObject.Length ];
			this.encapsulatedObject.CopyTo( objectCopy, 0 );
			frameCopy.encapsulatedObject = objectCopy;

			return frameCopy;
		}

		/// <summary>
		/// Writes the frame to a stream.
		/// </summary>
		/// <param name="stream">The stream to write to.</param>
		/// <param name="version">The ID3v2 version to use in writing the frame.</param>
		public override void WriteToStream( Stream stream, ID3Versions version )
		{
			switch ( version )
			{
				case ID3Versions.V2_2:
					break;

				case ID3Versions.V2_3:
				case ID3Versions.V2_4:
					WriteHeaderToStream( stream, version );
					stream.WriteByte( (byte) filename.TextEncodingType );

					stream.Write( mimeType.Bytes, 0, mimeType.Size );
					stream.Write( mimeType.Termination, 0, mimeType.Termination.Length );

					stream.Write( filename.Bytes, 0, filename.Size );
					stream.Write( filename.Termination, 0, filename.Termination.Length );

					stream.Write( description.Bytes, 0, description.Size );
					stream.Write( description.Termination, 0, description.Termination.Length );

					stream.Write( encapsulatedObject, 0, encapsulatedObject.Length );
					stream.Flush();
					break;

				default:
					throw new UnsupportedVersionException( version );
			}
		}
	}
}
